// SPDX-License-Identifier: Mulan PSL v2
/*
 * Copyright (c) 2025 Huawei Technologies Co., Ltd.
 * This software is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *         http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

//! 记录器模块单元测试

#[cfg(test)]
mod tests {
    use super::super::*;
    use crate::ipc::message::{Request, Argument, ArgumentFlag};
    use std::path::PathBuf;
    use std::fs;
    use tempfile::TempDir;

    /// 创建测试用的临时目录
    fn create_test_dir() -> TempDir {
        tempfile::TempDir::new().expect("Failed to create temp dir")
    }

    /// 创建测试用的Request
    fn create_test_request(method_id: u64) -> Request<'static> {
        let mut request = Request::new(method_id);
        
        // 添加一个简单的值参数
        let value = 42u32;
        let arg = Argument::with_value(&value, ArgumentFlag::ARG_IN);
        request.add_argument(arg);
        
        // 添加一个缓冲区参数
        let buffer = vec![1u8, 2, 3, 4, 5];
        let buf_arg = Argument::with_slice(&buffer, ArgumentFlag::ARG_IN | ArgumentFlag::ARG_OUT);
        request.add_argument(buf_arg);
        
        request
    }

    #[test]
    fn test_recorder_config_default() {
        let config = RecorderConfig::default();
        
        assert_eq!(config.output_path, PathBuf::from("requests.log"));
        assert!(matches!(config.format, RecordFormat::Protobuf));
        assert_eq!(config.buffer_size, 8192);
        assert_eq!(config.max_file_size, 100 * 1024 * 1024);
        assert!(config.auto_rotate);
    }

    #[test]
    fn test_logger_basic_functionality() -> Result<(), RecorderError> {
        let temp_dir = create_test_dir();
        let file_path = temp_dir.path().join("test_log.pb");
        
        let config = RecorderConfig {
            output_path: file_path.clone(),
            format: RecordFormat::Protobuf,
            buffer_size: 10,
            ..Default::default()
        };
        
        // 创建记录器并记录请求
        let mut logger = RequestLogger::new(config)?;
        
        let request1 = create_test_request(0x1001);
        let request2 = create_test_request(0x1002);
        
        logger.log_request(&request1)?;
        logger.log_request(&request2)?;
        logger.flush()?;
        
        // 检查统计信息
        let stats = logger.stats();
        assert_eq!(stats.total_requests, 2);
        assert_eq!(stats.flush_count, 1);
        
        // 关闭记录器
        logger.close()?;
        
        // 验证文件存在
        assert!(file_path.exists());
        
        Ok(())
    }

    #[test]
    fn test_logger_buffer_overflow() -> Result<(), RecorderError> {
        let temp_dir = create_test_dir();
        let file_path = temp_dir.path().join("test_overflow.pb");
        
        let config = RecorderConfig {
            output_path: file_path.clone(),
            format: RecordFormat::Protobuf,
            buffer_size: 2, // 很小的缓冲区
            ..Default::default()
        };
        
        let mut logger = RequestLogger::new(config)?;
        
        // 记录多个请求，应该触发自动刷新
        for i in 0..5 {
            let request = create_test_request(0x2000 + i);
            logger.log_request(&request)?;
        }
        
        let stats = logger.stats();
        assert!(stats.flush_count > 0); // 应该已经发生了刷新
        
        logger.close()?;
        
        Ok(())
    }

    #[test]
    fn test_player_basic_functionality() -> Result<(), RecorderError> {
        let temp_dir = create_test_dir();
        let file_path = temp_dir.path().join("test_playback.pb");
        
        // 首先创建一个记录文件
        {
            let config = RecorderConfig {
                output_path: file_path.clone(),
                format: RecordFormat::Protobuf,
                ..Default::default()
            };
            
            let mut logger = RequestLogger::new(config)?;
            
            for i in 0..3 {
                let request = create_test_request(0x3000 + i);
                logger.log_request(&request)?;
            }
            
            logger.close()?;
        }
        
        // 然后使用播放器读取
        let mut player = RequestPlayer::from_file(&file_path)?;
        
        // 检查文件头部
        let header = player.header();
        assert_eq!(header.magic, 0x52455152);
        assert_eq!(header.version, "1.0");
        
        // 读取记录
        let mut record_count = 0;
        while let Some(record) = player.next_record()? {
            assert!(record.method_id >= 0x3000 && record.method_id <= 0x3002);
            assert_eq!(record.arguments.len(), 2); // 两个参数
            
            record_count += 1;
        }
        
        assert_eq!(record_count, 3);
        
        Ok(())
    }

    #[test]
    fn test_player_rebuild_request() -> Result<(), RecorderError> {
        let temp_dir = create_test_dir();
        let file_path = temp_dir.path().join("test_rebuild.pb");
        
        let original_method_id = 0x4001;
        
        // 创建记录文件
        {
            let config = RecorderConfig {
                output_path: file_path.clone(),
                format: RecordFormat::Protobuf,
                ..Default::default()
            };
            
            let mut logger = RequestLogger::new(config)?;
            let request = create_test_request(original_method_id);
            logger.log_request(&request)?;
            logger.close()?;
        }
        
        // 读取并重建
        let mut player = RequestPlayer::from_file(&file_path)?;
        
        if let Some(record) = player.next_record()? {
            let rebuilt_request = player.rebuild_request(&record)?;
            
            // 验证重建的请求
            assert_eq!(rebuilt_request.method_id(), original_method_id);
            assert_eq!(rebuilt_request.arguments().len(), 2);
        } else {
            panic!("No record found");
        }
        
        Ok(())
    }

    #[test]
    fn test_protobuf_json_format_compatibility() -> Result<(), RecorderError> {
        let temp_dir = create_test_dir();
        let pb_path = temp_dir.path().join("test_compat.pb");
        let json_path = temp_dir.path().join("test_compat.json");
        
        let test_requests = vec![
            create_test_request(0x5001),
            create_test_request(0x5002),
        ];
        
        // 写入Protobuf格式
        {
            let config = RecorderConfig {
                output_path: pb_path.clone(),
                format: RecordFormat::Protobuf,
                ..Default::default()
            };
            
            let mut logger = RequestLogger::new(config)?;
            for request in &test_requests {
                logger.log_request(request)?;
            }
            logger.close()?;
        }
        
        // 写入JSON格式
        {
            let config = RecorderConfig {
                output_path: json_path.clone(),
                format: RecordFormat::Json,
                ..Default::default()
            };
            
            let mut logger = RequestLogger::new(config)?;
            for request in &test_requests {
                logger.log_request(request)?;
            }
            logger.close()?;
        }
        
        // 验证两种格式都能正确读取
        let mut pb_player = RequestPlayer::from_file_with_format(&pb_path, RecordFormat::Protobuf)?;
        let mut json_player = RequestPlayer::from_file_with_format(&json_path, RecordFormat::Json)?;
        
        let mut pb_records = Vec::new();
        let mut json_records = Vec::new();
        
        while let Some(record) = pb_player.next_record()? {
            pb_records.push(record);
        }
        
        while let Some(record) = json_player.next_record()? {
            json_records.push(record);
        }
        
        assert_eq!(pb_records.len(), json_records.len());
        assert_eq!(pb_records.len(), 2);
        
        // 比较方法ID（其他字段可能因为时间戳等原因不同）
        for (pb_rec, json_rec) in pb_records.iter().zip(json_records.iter()) {
            assert_eq!(pb_rec.method_id, json_rec.method_id);
            assert_eq!(pb_rec.arguments.len(), json_rec.arguments.len());
        }
        
        Ok(())
    }

    #[test]
    fn test_player_seek_functionality() -> Result<(), RecorderError> {
        let temp_dir = create_test_dir();
        let file_path = temp_dir.path().join("test_seek.pb");
        
        // 创建包含多个记录的文件
        {
            let config = RecorderConfig {
                output_path: file_path.clone(),
                format: RecordFormat::Protobuf,
                ..Default::default()
            };
            
            let mut logger = RequestLogger::new(config)?;
            
            for i in 0..5 {
                let request = create_test_request(0x6000 + i);
                logger.log_request(&request)?;
            }
            
            logger.close()?;
        }
        
        let mut player = RequestPlayer::from_file(&file_path)?;
        
        // 收集所有记录ID
        let mut record_ids = Vec::new();
        while let Some(record) = player.next_record()? {
            record_ids.push(record.record_id);
        }
        
        assert_eq!(record_ids.len(), 5);
        
        // 测试跳转到中间的记录
        let target_id = record_ids[2];
        player.seek_to_record(target_id)?;
        
        if let Some(record) = player.next_record()? {
            assert_eq!(record.record_id, target_id);
        } else {
            panic!("Failed to seek to target record");
        }
        
        Ok(())
    }

    #[test]
    fn test_player_timestamp_filtering() -> Result<(), RecorderError> {
        let temp_dir = create_test_dir();
        let file_path = temp_dir.path().join("test_filter.pb");
        
        // 创建记录文件
        {
            let config = RecorderConfig {
                output_path: file_path.clone(),
                format: RecordFormat::Protobuf,
                ..Default::default()
            };
            
            let mut logger = RequestLogger::new(config)?;
            
            for i in 0..3 {
                let request = create_test_request(0x7000 + i);
                logger.log_request(&request)?;
                
                // 添加小延迟确保时间戳不同
                std::thread::sleep(std::time::Duration::from_millis(10));
            }
            
            logger.close()?;
        }
        
        let mut player = RequestPlayer::from_file(&file_path)?;
        
        // 获取时间戳范围
        let start_time = std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)
            .unwrap()
            .as_nanos() as u64 - 1_000_000_000; // 1秒前
        
        let end_time = std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)
            .unwrap()
            .as_nanos() as u64;
        
        let filtered_records = player.filter_by_timestamp(start_time, end_time)?;
        
        // 应该能找到所有记录
        assert_eq!(filtered_records.len(), 3);
        
        // 验证时间戳在范围内
        for record in &filtered_records {
            assert!(record.timestamp_ns >= start_time);
            assert!(record.timestamp_ns <= end_time);
        }
        
        Ok(())
    }

    #[test]
    fn test_error_recovery() -> Result<(), RecorderError> {
        let temp_dir = create_test_dir();
        let file_path = temp_dir.path().join("test_error.pb");
        
        // 测试文件不存在的情况
        let result = RequestPlayer::from_file(&file_path);
        assert!(result.is_err());
        assert!(matches!(result.unwrap_err(), RecorderError::Io(_)));
        
        // 测试无效的记录器配置
        let invalid_config = RecorderConfig {
            output_path: PathBuf::from("/invalid/path/test.pb"),
            ..Default::default()
        };
        
        let result = RequestLogger::new(invalid_config);
        assert!(result.is_err());
        
        Ok(())
    }

    #[test]
    fn test_concurrent_access() -> Result<(), RecorderError> {
        use std::sync::{Arc, Mutex};
        use std::thread;
        
        let temp_dir = create_test_dir();
        let file_path = temp_dir.path().join("test_concurrent.pb");
        
        // 创建记录文件
        {
            let config = RecorderConfig {
                output_path: file_path.clone(),
                format: RecordFormat::Protobuf,
                ..Default::default()
            };
            
            let mut logger = RequestLogger::new(config)?;
            
            for i in 0..10 {
                let request = create_test_request(0x8000 + i);
                logger.log_request(&request)?;
            }
            
            logger.close()?;
        }
        
        // 测试并发读取
        let results = Arc::new(Mutex::new(Vec::new()));
        let mut handles = Vec::new();
        
        for _ in 0..3 {
            let file_path = file_path.clone();
            let results = Arc::clone(&results);
            
            let handle = thread::spawn(move || -> Result<(), RecorderError> {
                let mut player = RequestPlayer::from_file(&file_path)?;
                let mut count = 0;
                
                while let Some(_record) = player.next_record()? {
                    count += 1;
                }
                
                results.lock().unwrap().push(count);
                Ok(())
            });
            
            handles.push(handle);
        }
        
        // 等待所有线程完成
        for handle in handles {
            handle.join().unwrap()?;
        }
        
        // 验证所有线程都读取到相同数量的记录
        let results = results.lock().unwrap();
        assert_eq!(results.len(), 3);
        for &count in results.iter() {
            assert_eq!(count, 10);
        }
        
        Ok(())
    }

    #[test]
    fn test_protobuf_serialization_performance() -> Result<(), RecorderError> {
        use std::time::Instant;
        
        let temp_dir = create_test_dir();
        let file_path = temp_dir.path().join("test_perf.pb");
        
        let config = RecorderConfig {
            output_path: file_path.clone(),
            format: RecordFormat::Protobuf,
            buffer_size: 1000,
            ..Default::default()
        };
        
        let mut logger = RequestLogger::new(config)?;
        
        let start_time = Instant::now();
        let request_count = 1000;
        
        // 记录大量请求
        for i in 0..request_count {
            let request = create_test_request(0x9000 + i);
            logger.log_request(&request)?;
        }
        
        logger.close()?;
        let duration = start_time.elapsed();
        
        // 性能要求：每个记录的处理时间应该小于100微秒
        let avg_time_per_record = duration / request_count as u32;
        println!("Average time per record: {:?}", avg_time_per_record);
        
        assert!(avg_time_per_record.as_micros() < 100, 
                "Performance requirement not met: {}μs per record", 
                avg_time_per_record.as_micros());
        
        Ok(())
    }

    #[test]
    fn test_large_file_handling() -> Result<(), RecorderError> {
        let temp_dir = create_test_dir();
        let file_path = temp_dir.path().join("test_large.pb");
        
        let config = RecorderConfig {
            output_path: file_path.clone(),
            format: RecordFormat::Protobuf,
            max_file_size: 1024, // 很小的限制用于测试
            ..Default::default()
        };
        
        let mut logger = RequestLogger::new(config)?;
        
        // 记录请求直到文件大小限制
        for i in 0..100 {
            let request = create_test_request(0xa000 + i);
            logger.log_request(&request)?;
            
            // 检查文件大小（简化测试，实际实现可能需要文件轮转）
            if i > 50 {
                break; // 避免无限循环
            }
        }
        
        logger.close()?;
        
        // 验证能够正常读取
        let mut player = RequestPlayer::from_file(&file_path)?;
        let mut count = 0;
        
        while let Some(_record) = player.next_record()? {
            count += 1;
        }
        
        assert!(count > 0);
        
        Ok(())
    }
}